#include "analysis.h"

analysis::analysis()
{

}

//字节反转函数
void byteReverse(QString &coils)
{
    // 定义临时字符变量
    QChar temp;

    for(int i=0; i < 4; i++)
    {
        temp = coils[i];        // 将第i个元素存入临时字符变量
        coils[i] = coils[8-i-1];  // 将第i个字符元素和第n-i-1个元素对调
        coils[8-i-1] = temp;    // 将临时字符变量的值赋给第n-i-1个元素
    }
}

//连接两个quint8数据为一个quint16数据
quint16 BondTwoUint8ToUint16(quint8 preNum, quint8 afterNum)
{
    quint16 bondNum = (preNum << 8) | afterNum;
    return bondNum;
}

QString HexByteArrayToBinString(QByteArray DataArray)
{
    //2进制字符串的长度
    quint16 DataArrayLength;
    DataArrayLength = DataArray.size();

    QString res;
    for(int i = 0; i < DataArrayLength; i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)DataArray.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        res += str;
    }
    return res;
}

//接收报文并处理
void analysis::receiveModbus(QByteArray msg,quint8 addr)
{
     readseting = new QSettings("Data.ini", QSettings::IniFormat);
    if(msg.isEmpty()==false)
    {
        recvModbusmsg = msg;
        mb_addr = addr;
        MB_satae state =parse_Modbus_Msg(recvModbusmsg);
        //打印当前状态
        qDebug()<< state;
        parseModbusMbSatae(state);
    }
}
//读取状态
MB_satae analysis::parse_Modbus_Msg(QByteArray ba)
{
    //判断帧的长度
    if(ba.length()>259)
    {
        errorMsg="报文长度过长";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }
    else if(ba.length()<12)
    {
        errorMsg = "报文长度过短";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }
    //读取报文数据段字节计数
    quint8 rdsize = (quint8)ba.at(5);
    //读取报文数据段长度
    QByteArray drsize = ba.mid(6,ba.size());
    //拷贝协议标识符
   Copy_protocol = ((quint8)ba[2])*256+(quint8)ba[3];

   //判断协议标识符
    if(Copy_protocol!=0)
    {
        errorMsg="无响应，标识符不正确";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }

    //判断ADU长度
    quint16 AduLength;
    AduLength = ((quint8)ba[4]<<8)|(quint8)ba[5];
//    if(AduLength>(ba.size()-6))
//    {
//        quint8 add;
//        add = AduLength-(ba.size()-6);
//        errorMsg = "请求报文字节长度错误，字节长度过短，数据少"+QString::number(add)+"位"+"\n";
////        errorMsg = "无响应，报文长度过短，数据少"+QString::number(add)+"位"+"\n";
//        return MB_SLAVE_STATE_PACKET_OTHER;
//    }
//    else if(AduLength<(ba.size()-6))
//    {
//        quint8 add;
//        add = (ba.size()-6)-AduLength;
//        errorMsg = "请求报文字节长度错误!，字节长度过长，数据多"+QString::number(add)+"位"+"\n";
////        errorMsg = "无响应，报文长度过长，数据多"+QString::number(add)+"位"+"\n";
//        return MB_SLAVE_STATE_PACKET_OTHER;
//    }

    if(AduLength!=(ba.size()-6))
    {
        errorMsg = "字节长度错误，请求报文中字节长度与实际应用数据单元长度不一致!";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }

    //判断从机地址
    if(ba[6]!=mb_addr)
    {
        errorMsg = "不是本机的地址，从机地址错误";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }

    //判断功能码，进行深层解析
    switch(ba[7])
    {
        case 0x01: mb_code =0x01;
        //起始地址
        mb_startaddr = ((quint8)ba[8])*256+(quint8)ba[9];
        //数据量
        mb_num = ((quint8)ba[10])*256+(quint8)ba[11];
        if(mb_num>2000)
        {
            //03错误异常
            errorMsg="03数量异常，线圈读取数量超过2000";
            return MB_SLAVE_STATE_DATA_ERROR;
        }
        else if(mb_num==0)
        {
            errorMsg = "03数量异常，线圈读取数量为0";
            return MB_SLAVE_STATE_DATA_ERROR;
        }
        else if((mb_startaddr+mb_num-1)>65535)
        {
            errorMsg="02异常数据 线圈查询非法,请求报文中起始地址后可读取的线圈数量小于查询数量";
            return MB_SLAVE_STATE_DATAADDR_ERROR;
        }
        else if(ba.length()>12)
        {
            errorMsg = "读取报文长度过长";
            return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else if (rdsize!=drsize.size())
        {
            errorMsg = "字节数与数据段不正确";
            return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else
        {
            return MB_SLAVE_STATE_PACKET_PROCESS;
        }
        break;

     case 0x03: mb_code = 0x03;
        //起始地址
        mb_startaddr =  ((quint8)ba[8])*256+(quint8)ba[9];
        //数据量
        mb_num = ((quint8)ba[10])*256+(quint8)ba[11];
        //判断数量
        if(mb_num>125)
        {
            errorMsg="03数量异常，读取寄存器数量超过125";
            return MB_SLAVE_STATE_DATA_ERROR;
        }
        else if(mb_num==0)
        {
            errorMsg = "03数量异常，读取寄存器数量不能为0";
            return MB_SLAVE_STATE_DATA_ERROR;
        }
        else if((mb_startaddr+mb_num-1)>65535)
        {
            errorMsg = "02异常数据 寄存器查询非法,请求报文中起始地址后可读取的寄存器数量小于查询数量";
        }
        else if(ba.length()>12)
        {
            errorMsg = "读取报文长度过长";
            return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else if (rdsize!=drsize.size())
        {
            errorMsg = "字节数与数据段不正确";
            return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else
        {
            return MB_SLAVE_STATE_PACKET_PROCESS;
        }
        break;
     case 0x0f: mb_code = 0x0f;
        //写数据字节数
        coilsize = (quint8)ba.at(12);
        //数据段字节数
        csizes = ba.mid(13,ba.size());
        //数量
        wnum = BondTwoUint8ToUint16((quint8)ba.at(10),(quint8)ba.at(11));
        //起始地址
        mb_startaddr = ((quint8)ba[8])*256+(quint8)ba[9];
        //数据量
        mb_num = ((quint8)ba[10])*256+(quint8)ba[11];
        //写入数量判断
        if(mb_num>1968)
        {
            errorMsg="03数量异常，写入线圈数量大于1968";
            return  MB_SLAVE_STATE_DATA_ERROR;
        }
        else if (mb_num==0)
        {
            errorMsg = "03数量异常，写入线圈数量不能为0";
              return  MB_SLAVE_STATE_DATA_ERROR;
        }
        else if ((mb_startaddr+mb_num-1)>65535)
        {
             errorMsg = "02异常数据 线圈写入非法,请求报文中起始地址后可读取的线圈数量小于写入数量";
             return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else if(coilsize!=csizes.size()||((wnum+7)/8)!=coilsize)
        {
            errorMsg = "写入字节与数据段长度或数量与字节数不正确";
            return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else
        {
            return MB_SLAVE_STATE_PACKET_PROCESS;
        }

    break;


    case 0x10: mb_code = 0x10;
        coilsize = (quint8)ba.at(12);
        csizes = ba.mid(13,ba.size());
        wnum = BondTwoUint8ToUint16((quint8)ba.at(10),(quint8)ba.at(11));
        //起时地址
        mb_startaddr = ((quint8)ba[8])*256+(quint8)ba[9];
        //数据量
        mb_num = ((quint8)ba[10])*256+(quint8)ba[11];
        //判断数量
        if(mb_num>123)
        {
            errorMsg = "03数量异常，写入寄存器数量不能大于123";
            return MB_SLAVE_STATE_DATA_ERROR;
        }
        else if(mb_num==0)
        {
            errorMsg = "03数量异常，写入寄存器不能为0";
            return MB_SLAVE_STATE_DATA_ERROR;
        }
        else if ((mb_startaddr+mb_num-1)>65535)
        {
            errorMsg = "02异常数据 寄存器写入非法,请求报文中起始地址后可写入的寄存器数量小于写入数量";
        }
        else if(coilsize!=csizes.size())
        {
            errorMsg = "写入字节与数据段长度或数量不正确";
            return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else if ((wnum*2!=coilsize))
        {
            errorMsg = "字节数不正确";
            return MB_SLAVE_STATE_PACKET_SIZELENTH;
        }
        else
        {
            return MB_SLAVE_STATE_PACKET_PROCESS;
        }
    break;
    default:
        errorMsg = "功能码不支持 ";
        mb_code = ba[7];
        return MB_SLAVE_STATE_FUNCTION_ERROR;
        break;
    }
}
//状态处理
void analysis::parseModbusMbSatae(MB_satae satae)
{
    switch(satae)
    {
    case MB_SLAVE_STATE_PACKET_PROCESS:
        switch(mb_code)
        {
        case 1:analysis01();
            break;
        case 3:analysis03();
            break;
        case 15:analysis0f();
            break;
        case 16:analysis10();
            break;
        }
        break;
        //异常处理
    case MB_SLAVE_STATE_DATAADDR_ERROR:
        parse_Modbus_Exception_Handling02();
        emit toUishowMsg(errorMsg);
        break;
    case MB_SLAVE_STATE_DATA_ERROR:
        parse_Modbus_Exception_Handling03();
        emit toUishowMsg(errorMsg);
        break;
    case MB_SLAVE_STATE_FUNCTION_ERROR:
        parse_Modbus_Exception_Handling01();
        emit toUishowMsg(errorMsg);
        break;
    case MB_SLAVE_STATE_PACKET_SIZELENTH:
        emit toUishowMsg(errorMsg);
        break;
    case MB_SLAVE_STATE_PACKET_OTHER:
        emit toUishowMsg(errorMsg);
        break;
    }
}

void analysis::analysis01()
{
    QByteArray ba;
    quint16 num =((quint8)recvModbusmsg[10])*256+(quint8)recvModbusmsg[11];
    quint16 startaddr =((quint8)recvModbusmsg[8])*256+(quint8)recvModbusmsg[9];
    GetData0X01(ba,startaddr,num);
    //报文头组装
    //事务及协议
    sendModbusmsg[0]=recvModbusmsg[0];
    sendModbusmsg[1]=recvModbusmsg[1];
    sendModbusmsg[2]=recvModbusmsg[2];
    sendModbusmsg[3]=recvModbusmsg[3];
    //字节长度
    sendModbusmsg[4]=(3+ba.size())>>8;
    sendModbusmsg[5]=(3+ba.size())&0xFF;
    //单元标识符
    sendModbusmsg[6]=recvModbusmsg[6];
    //功能码
    sendModbusmsg[7]=recvModbusmsg[7];
    //字节计数
    sendModbusmsg[8]=(quint8)ba.size();
    //状态值
    for(int i=9,j=0;j<ba.size();j++)
    {
        sendModbusmsg[i++]=(quint8)ba.at(j);
    }
    //显示读出的数据
    ReadCoilPackMsgToShow(startaddr,num,ba);
    emit toUishowMsgPack(sendModbusmsg);
    emit analysis_over(sendModbusmsg);
    sendModbusmsg.clear();
}

void analysis::analysis03()
{
    quint16 num =((quint8)recvModbusmsg[10])*256+(quint8)recvModbusmsg[11];
    quint16 startaddr =((quint8)recvModbusmsg[8])*256+(quint8)recvModbusmsg[9];
    //报文头组装
    //事务及协议
    sendModbusmsg[0]=recvModbusmsg[0];
    sendModbusmsg[1]=recvModbusmsg[1];
    sendModbusmsg[2]=recvModbusmsg[2];
    sendModbusmsg[3]=recvModbusmsg[3];
    //字节长度
    sendModbusmsg[4]=(3+num*2)>>8;
    sendModbusmsg[5]=(3+num*2)&0xFF;
    //单元标识符
    sendModbusmsg[6]=recvModbusmsg[6];
    //功能码
    sendModbusmsg[7]=recvModbusmsg[7];
    //字节计数
    sendModbusmsg[8]=(quint8)num*2;
    //状态值
    for(quint16 i=9,z=0,j=startaddr;z<num;z++,j++)
    {
        //读出寄存器数据
        QString registerData = readseting->value("Section" + QString::number(j+1) + "/regi").toString();
        sendModbusmsg[i++]=((quint16)registerData.toInt())>>8;
        sendModbusmsg[i++]=((quint16)registerData.toInt())&0xFF;
        msg.push_back((quint16)registerData.toInt());
    }
    ReadRegsPackMsgToShow(startaddr,num,msg);
    msg.clear();
    emit toUishowMsgPack(sendModbusmsg);
    emit analysis_over(sendModbusmsg);
    sendModbusmsg.clear();
}
void analysis::analysis0f()
{
    QByteArray ba;
    quint16 num = recvModbusmsg[12];
    quint16 datanum = ((quint8)recvModbusmsg[10])*256+(quint8)recvModbusmsg[11];
    quint16 startaddr = ((quint8)recvModbusmsg[8])*256+(quint8)recvModbusmsg[9];
    quint16 sizenum = ((quint8)recvModbusmsg[4])*256+(quint8)recvModbusmsg[5];
    //读取数据
    for(int i=0;i<num;i++)
    {
        ba[i]=recvModbusmsg[13+i];
    }
    //转化为二进制字符串
    HexByteArrayToBinString(ba);
    //更新表格
    //emit wirtTablec(datanum,startaddr,HexByteArrayToBinString(ba));
    //写入文件
    WriteData0X0F(startaddr,HexByteArrayToBinString(ba));
    //读出写入数据
    WirteCoilPackMsgToShow(startaddr,datanum,ba);
    //回应报文
    ba = recvModbusmsg.mid(0,12);
    ba[4] = (sizenum-num-1)>>8;
    ba[5] = (sizenum-num-1)&0xFF;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
    bac.clear();
}
void analysis::analysis10()
{
    QByteArray ba;
    quint16 num = recvModbusmsg[12];
    quint16 startaddr = ((quint8)recvModbusmsg[8])*256+(quint8)recvModbusmsg[9];
    quint16 sizenum = ((quint8)recvModbusmsg[4])*256+(quint8)recvModbusmsg[5];
    //读取数据
    for(int j=13,z=0,k=startaddr;z<num/2;k++,z++)
    {
        quint16 coildata=((quint8)recvModbusmsg[j++])*256+(quint8)recvModbusmsg[j++];
        bar.push_back(coildata);
        //写入文件
        QString s = "Section" + QString::number(k+1) + "/regi";
        readseting->setValue(s,coildata);
    }
    //更新表格
    emit wirtTabler(num/2,startaddr,bar);

    WirteRegsPackMsgToShow(startaddr,num/2,bar);
    //回应报文
    ba = recvModbusmsg.mid(0,12);
    ba[4] = (sizenum-num-1)>>8;
    ba[5] = (sizenum-num-1)&0xFF;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
    sendModbusmsg.clear();
    bar.clear();
}

//异常处理
void analysis::parse_Modbus_Exception_Handling01()
{
    QByteArray ba;
    //回应报文
    ba = recvModbusmsg.mid(0,8);
    ba[4] = (3)>>8;
    ba[5] = (3)&0xFF;
    ba[7] = (mb_code+0x80);
    ba[8] = 0x01;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
}
void analysis::parse_Modbus_Exception_Handling02()
{
    QByteArray ba;
    //回应报文
    ba = recvModbusmsg.mid(0,8);
    ba[4] = (3)>>8;
    ba[5] = (3)&0xFF;
    ba[7] = (mb_code+0x80);
    ba[8] = 0x02;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
}
void analysis::parse_Modbus_Exception_Handling03()
{
    QByteArray ba;
    //回应报文
    ba = recvModbusmsg.mid(0,8);
    ba[4] = (3)>>8;
    ba[5] = (3)&0xFF;
    ba[7] = (mb_code+0x80);
    ba[8] = 0x03;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
}

void analysis::GetData0X01(QByteArray &coilsDataArr,quint16 BeginAddress,quint16 Number)
{
    //声明读取的数据字符串
    QString getDataString;
    quint8 responseMessageByteNum;
    //求响应报文字节数
    responseMessageByteNum = (quint8)((Number + 7) / 8);

    //从数据表中读取需要数量的线圈数据,形成二进制形式字符串
    for(quint32 i = BeginAddress; i < (BeginAddress + Number); i++)
    {
        //读出线圈数据
     QString buffer = readseting->value("Section" + QString::number(i+1) + "/coil").toString();
        if(buffer == "1")
        {
            getDataString += "1";
        }
        else
        {
            getDataString += "0";
        }
    }
    //二进制字符串补0
    for(int i = 1; i <= (8*responseMessageByteNum - Number); i++)
    {
        getDataString += "0";
    }
    //coilsDataArr.resize(responseMessageByteNum);
    //将二进制字符串按字节填入响应报文数组
    for(int i = 0; i < responseMessageByteNum; i++)
    {
        //对8位1字节进行反转处理
        QString buffer = getDataString.mid((8 * i),8);
        //字节反转
        byteReverse(buffer);
        //存入响应报文数组
        coilsDataArr[i] = buffer.toInt(NULL,2);
    }
}

void analysis::ReadCoilPackMsgToShow(quint16 startaddr,quint16 num,QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    for(quint8 i=0;i<size;i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)msg.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        msgs += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    msgs = msgs.left(num);
    emit toUishowMsg("成功读出线圈的数据\n");
    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    msgs.clear();
}

//报文寄存器数据读出提示
void analysis::ReadRegsPackMsgToShow(quint16 startaddr,quint16 num,QVector<quint16> msg)
{
    quint8 size = msg.size();
    QString msgs;
    quint16 data;
    for(quint8 i=0;i<size;i++)
    {
        QString str;
        data= msg.at(i);
        str = QString("%1 ").arg(data);
        msgs+=str;
    }
    emit toUishowMsg("成功读出寄存器的数据\n");
    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    msgs.clear();
    msg.clear();
}
//报文线圈数据写入提示
void analysis::WirteCoilPackMsgToShow(quint16 startaddr,quint16 num,QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    for(quint8 i=0;i<size;i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)msg.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        msgs += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    msgs = msgs.left(num);
    emit toUishowMsg("成功写入线圈的数据\n");
    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    msgs.clear();
}
//报文寄存器数据写入提示
void analysis::WirteRegsPackMsgToShow(quint16 startaddr,quint16 num,QVector<quint16> msg)
{
    quint8 size = msg.size();
    QString msgs;
    quint16 data;
    for(quint8 i=0;i<size;i++)
    {
        QString str;
        data= (quint16)msg.at(i);
        str = QString("%1 ").arg(data);
        msgs+=str;
    }
    emit toUishowMsg("成功写入寄存器的数据\n");
//    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    msgs.clear();
}

//0x0f功能码 写入线圈数据  单个线圈
void analysis::WriteData0X0F(quint16 satrt,QString CoilData)
{
    //更新ini文件数据
    for(int j=0,k=satrt;j<CoilData.length();j++,k++)
    {
        QString s = "Section" + QString::number(k+1) + "/coil";
        quint8 coildata;
        if(CoilData.at(j)=='1')
        {
            coildata = 1;
        }
        else
        {
            coildata = 0;
        }
        readseting->setValue(s,coildata);
    }
}







